1484237749 by Unknown

1484237749 by Unknown

Author:Unknown
Language: eng
Format: epub
Published: 2018-10-30T12:05:29+00:00


Chapter 5 List stories

map(ids => ids.slice(offset, offset + limit)),

mergeMap((ids: any[]) => combineLatest(...(ids.map

(id => this.db.object('/v0/item/' + id).valueChanges())))),

map((items: any) => ({

offset,

limit,

total: limit,

results: items,

}))

);

}

}

Alternative Model and Service Implementation

The current implementation of ItemService uses Observable operators

to watch for changes in the Firebase database and emit values. However,

some of those updates may not be necessary. When a story is updated, for example; when the score is updated; or new comments are added, a new

Items object that contains all items is emitted from the Observable<Items> object and triggers an update of the whole UI. This is because the operator combineLatest emits a new combined value when any source Observable

emits a value. This frequent UI update is not a good user experience. We can improve the performance by changing the data model.

Currently, we use Item[] in model Items to represent the items, which

means all Item objects need to be resolved asynchronously before creating the Items object for the ItemsComponent to render. This makes users wait longer than expected. We can update the model Items to use Observable<Item>[]

as the type of items; see Listing 5-44. Because each item is represented as its own Observable<Item> object, it can update itself separately. After updating the model, a new Items object is only emitted when the Observable of

this.db.list('/v0/topstories').valueChanges() emits a new array of ids.

170

Chapter 5 List stories

Listing 5-44. Updated model Items

import { Observable } from 'rxjs';

import { Item } from './Item';

export interface Items {

offset: number;

limit: number;

total?: number;

results: Observable<Item>[];

}

If we update the model, we can simplify the implementation of the

ItemService; see Listing 5-45. After slicing the original array of item ids, the operator distinctUntilChanged is used to make sure that duplicate

item ids won’t be emitted to trigger unnecessary UI updates. Then the

operator map is used to transform the array of item ids into an array of Observable<Item>.

Listing 5-45. Updated ItemService

import { Injectable } from '@angular/core';

import * as isEqual from 'lodash.isequal';

import { Observable } from 'rxjs';

import { map, distinctUntilChanged } from 'rxjs/operators';

import { Items } from '../../models/items';

import { AngularFireDatabase } from '@angular/fire/database';

@Injectable()

export class ItemService {

constructor(private db: AngularFireDatabase) {}

171

Chapter 5 List stories

load(offset: number, limit: number): Observable<Items> {

return this.db.list('/v0/topstories')

.valueChanges()

.pipe(

map(ids => ids.slice(offset, offset + limit)),

distinctUntilChanged(isEqual),

map((ids: any[]) => ids.map(id => this.db.object('/v0/

item/' + id).valueChanges())),

map((items: any) => ({

offset,

limit,

total: limit,

results: items,

}))

);

}

}

After updating the model, the implementation of ItemService can be

simplified. However, it makes the implementation of ItemComponent

complicated. As the type of the property item is changed from Item to

Observable<Item>, ItemComponent needs to subscribe to the Observable and re-render itself when a new value is emitted. This can be done using the pipe async.

The changes to model and ItemComponent are an alternative way to

implement the user story. However, this implementation violates one

fundamental principle of designing components like ItemComponent.

These components should only have pure rendering logic. The logic of

handling Observables in ItemComponent makes it hard to test. This section only provides information about potential alternative implementations.

The actual implementation of the example still uses the old model.

The aforementioned performance issue will be solved by using state

management frameworks in Chapter 6.

172



Download



Copyright Disclaimer:
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.